{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "hkZw98BK0AKv"
   },
   "outputs": [],
   "source": [
    "# Copyright 2024 Google LLC\n",
    "#\n",
    "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "#     https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "07d50ba6b79d"
   },
   "source": [
    "# Multimodal Prompting with Gemini: Working with Audio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AGhNH-y9z5EZ"
   },
   "source": [
    "<table align=\"left\">\n",
    "<td style=\"text-align: center\">\n",
    "<a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/applied-ai-engineering-samples/blob/main/genai-on-vertex-ai/gemini/prompting_recipes/multimodal/multimodal_prompting_audio.ipynb\">\n",
    "<img src=\"https://cloud.google.com/ml-engine/images/colab-logo-32px.png\" alt=\"Google Colaboratory logo\"><br> Run in Colab\n",
    "</a>\n",
    "</td>\n",
    "      <td style=\"text-align: center\">\n",
    "    <a href=\"https://console.cloud.google.com/vertex-ai/colab/import/https:%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fapplied-ai-engineering-samples%2Fmain%2Fgenai-on-vertex-ai%2Fgemini%2Fprompting_recipes%2Fmultimodal%2Fmultimodal_prompting_audio.ipynb\">\n",
    "      <img width=\"32px\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" alt=\"Google Cloud Colab Enterprise logo\"><br> Open in Colab Enterprise\n",
    "    </a>\n",
    "  </td>\n",
    "<td style=\"text-align: center\">\n",
    "<a href=\"https://console.cloud.google.com/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/applied-ai-engineering-samples/main/genai-on-vertex-ai/gemini/prompting_recipes/multimodal/multimodal_prompting_audio.ipynb\">\n",
    "<img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI logo\"><br> Open in Vertex AI Workbench\n",
    "</a>\n",
    "</td>    \n",
    "<td style=\"text-align: center\">\n",
    "<a href=\"https://github.com/GoogleCloudPlatform/applied-ai-engineering-samples/blob/main/genai-on-vertex-ai/gemini/prompting_recipes/multimodal/multimodal_prompting_audio.ipynb\">\n",
    "<img src=\"https://cloud.google.com/ml-engine/images/github-logo-32px.png\" alt=\"GitHub logo\"><br> View on GitHub\n",
    "</a>\n",
    "</td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "dqS4jWxr0Eyz"
   },
   "source": [
    "| | |\n",
    "|-|-|\n",
    "| Author(s) | [Michael Chertushkin](https://github.com/misha-chertushkin) |\n",
    "| Reviewer(s) | [Rajesh Thallam](https://github.com/rthallam), [Skander Hannachi](https://github.com/skanderhn)  |\n",
    "| Last updated | 2024-09-16 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "t7rHg_1odsMM"
   },
   "source": [
    "# Overview\n",
    "\n",
    "---\n",
    "\n",
    "Gemini 2.0 models supports adding image, audio, video, and PDF files in text or chat prompts for a text or code response. Gemini 2.0 Flash supports up to 1 Million input tokens with up to 8.4 hours length of audio per prompt. You can add audio to Gemini requests to perform [audio analysis tasks](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/audio-understanding) such as transcribing audio, audio chapterization (or localization), key event detection, audio translation and more. \n",
    "\n",
    "---\n",
    "\n",
    "In this notebook we cover prompting recipes and strategies for working with Gemini on audio files and show some examples on the way. This notebook is organized as follows:\n",
    "\n",
    "- Audio Understanding\n",
    "- Effective prompting\n",
    "- Key event detection\n",
    "- Using System instruction\n",
    "- Generating structured output\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "acd63312c2f4"
   },
   "source": [
    "# Getting Started\n",
    "\n",
    "The following steps are necessary to run this notebook, no matter what notebook environment you're using.\n",
    "\n",
    "If you're entirely new to Google Cloud, [get started here](https://cloud.google.com/docs/get-started)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "13e6fde93ea3"
   },
   "source": [
    "## Google Cloud Project Setup\n",
    "\n",
    "1. [Select or create a Google Cloud project](https://console.cloud.google.com/cloud-resource-manager). When you first create an account, you get a $300 free credit towards your compute/storage costs.\n",
    "1. [Make sure that billing is enabled for your project](https://cloud.google.com/billing/docs/how-to/modify-project).\n",
    "1. [Enable the Service Usage API](https://console.cloud.google.com/apis/library/serviceusage.googleapis.com)\n",
    "1. [Enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
    "1. [Enable the Cloud Storage API](https://console.cloud.google.com/flows/enableapi?apiid=storage.googleapis.com)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d9b5ae4999b9"
   },
   "source": [
    "## Google Cloud Permissions\n",
    "\n",
    "**To run the complete Notebook, including the optional section, you will need to have the [Owner role](https://cloud.google.com/iam/docs/understanding-roles) for your project.**\n",
    "\n",
    "If you want to skip the optional section, you need at least the following [roles](https://cloud.google.com/iam/docs/granting-changing-revoking-access):\n",
    "* **`roles/serviceusage.serviceUsageAdmin`** to enable APIs\n",
    "* **`roles/iam.serviceAccountAdmin`** to modify service agent permissions\n",
    "* **`roles/aiplatform.user`** to use AI Platform components\n",
    "* **`roles/storage.objectAdmin`** to modify and delete GCS buckets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2b203ddf1cdc"
   },
   "source": [
    "## Install Vertex AI SDK for Python and other dependencies (If Needed)\n",
    "\n",
    "The list `packages` contains tuples of package import names and install names. If the import name is not found then the install name is used to install quitely for the current user.## Install Vertex AI SDK for Python and other dependencies (If Needed)\n",
    "\n",
    "The list `packages` contains tuples of package import names and install names. If the import name is not found then the install name is used to install quitely for the current user."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "514241a24fa4"
   },
   "outputs": [],
   "source": [
    "! pip install google-cloud-aiplatform --upgrade --quiet --user"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5b187dc025e0"
   },
   "source": [
    "## Restart Runtime\n",
    "\n",
    "To use the newly installed packages in this Jupyter runtime, you must restart the runtime. You can do this by running the cell below, which will restart the current kernel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "8b08062f2883"
   },
   "outputs": [],
   "source": [
    "# Restart kernel after installs so that your environment can access the new packages\n",
    "import IPython\n",
    "\n",
    "app = IPython.Application.instance()\n",
    "app.kernel.do_shutdown(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6791e371ace9"
   },
   "source": [
    "## Authenticate\n",
    "\n",
    "If you're using Colab, run the code in the next cell. Follow the popups and authenticate with an account that has access to your Google Cloud [project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects).\n",
    "\n",
    "If you're running this notebook somewhere besides Colab, make sure your environment has the right Google Cloud access. If that's a new concept to you, consider looking into [Application Default Credentials for your local environment](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev) and [initializing the Google Cloud CLI](https://cloud.google.com/docs/authentication/gcloud). In many cases, running `gcloud auth application-default login` in a shell on the machine running the notebook kernel is sufficient.\n",
    "\n",
    "More authentication options are discussed [here](https://cloud.google.com/docs/authentication)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "51cabca59af0"
   },
   "outputs": [],
   "source": [
    "# Colab authentication.\n",
    "import sys\n",
    "\n",
    "if \"google.colab\" in sys.modules:\n",
    "    from google.colab import auth\n",
    "\n",
    "    auth.authenticate_user()\n",
    "    print(\"Authenticated\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4mmDittp23Gp"
   },
   "source": [
    "## Set Google Cloud project information and Initialize Vertex AI SDK\n",
    "\n",
    "To get started using Vertex AI, you must have an existing Google Cloud project and [enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
    "\n",
    "Learn more about [setting up a project and a development environment](https://cloud.google.com/vertex-ai/docs/start/cloud-environment).\n",
    "\n",
    "Make sure to change `PROJECT_ID` in the next cell. You can leave the values for `REGION` unless you have a specific reason to change them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "xOwys5I724od",
    "tags": []
   },
   "outputs": [],
   "source": [
    "import vertexai\n",
    "\n",
    "PROJECT_ID = \"[your-project-id]\"  # @param {type:\"string\"}\n",
    "REGION = \"us-central1\"  # @param {type:\"string\"}\n",
    "\n",
    "vertexai.init(project=PROJECT_ID, location=REGION)\n",
    "print(\"Vertex AI SDK initialized.\")\n",
    "print(f\"Vertex AI SDK version = {vertexai.__version__}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "89c6c77513de"
   },
   "source": [
    "## Import Libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "ZZr3aL5G3iuy",
    "tags": []
   },
   "outputs": [],
   "source": [
    "from vertexai.generative_models import (GenerationConfig, GenerativeModel,\n",
    "                                        HarmBlockThreshold, HarmCategory, Part)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d9e80e805ceb"
   },
   "source": [
    "## Define Utility functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "cd6eda4a234c",
    "tags": []
   },
   "outputs": [],
   "source": [
    "import http.client\n",
    "import textwrap\n",
    "import typing\n",
    "import urllib.request\n",
    "\n",
    "from google.cloud import storage\n",
    "from IPython import display\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "\n",
    "def wrap(string, max_width=80):\n",
    "    return textwrap.fill(string, max_width)\n",
    "\n",
    "\n",
    "def get_bytes_from_url(url: str) -> bytes:\n",
    "    with urllib.request.urlopen(url) as response:\n",
    "        response = typing.cast(http.client.HTTPResponse, response)\n",
    "        bytes = response.read()\n",
    "    return bytes\n",
    "\n",
    "\n",
    "def get_bytes_from_gcs(gcs_path: str):\n",
    "    bucket_name = gcs_path.split(\"/\")[2]\n",
    "    object_prefix = \"/\".join(gcs_path.split(\"/\")[3:])\n",
    "    storage_client = storage.Client()\n",
    "    bucket = storage_client.bucket(bucket_name)\n",
    "    blob = bucket.get_blob(object_prefix)\n",
    "    return blob.download_as_bytes()\n",
    "\n",
    "\n",
    "def display_image(image_url: str, width: int = 300, height: int = 200):\n",
    "    if image_url.startswith(\"gs://\"):\n",
    "        image_bytes = get_bytes_from_gcs(image_url)\n",
    "    else:\n",
    "        image_bytes = get_bytes_from_url(image_url)\n",
    "    display.display(display.Image(data=image_bytes, width=width, height=height))\n",
    "\n",
    "\n",
    "def display_video(video_url: str, width: int = 300, height: int = 200):\n",
    "    if video_url.startswith(\"gs://\"):\n",
    "        video_bytes = get_bytes_from_gcs(video_url)\n",
    "    else:\n",
    "        video_bytes = get_bytes_from_url(video_url)\n",
    "    display.display(\n",
    "        display.Video(\n",
    "            data=video_bytes,\n",
    "            width=width,\n",
    "            height=height,\n",
    "            embed=True,\n",
    "            mimetype=\"video/mp4\",\n",
    "        )\n",
    "    )\n",
    "\n",
    "\n",
    "def display_audio(audio_url: str, width: int = 300, height: int = 200):\n",
    "    if audio_url.startswith(\"gs://\"):\n",
    "        audio_bytes = get_bytes_from_gcs(audio_url)\n",
    "    else:\n",
    "        audio_bytes = get_bytes_from_url(audio_url)\n",
    "    display.display(display.Audio(data=audio_bytes, embed=True))\n",
    "\n",
    "\n",
    "def print_prompt(contents: list[str | Part]):\n",
    "    for content in contents:\n",
    "        if isinstance(content, Part):\n",
    "            if content.mime_type.startswith(\"image\"):\n",
    "                display_image(image_url=content.file_data.file_uri)\n",
    "            elif content.mime_type.startswith(\"video\"):\n",
    "                display_video(video_url=content.file_data.file_uri)\n",
    "            elif content.mime_type.startswith(\"audio\"):\n",
    "                display_audio(audio_url=content.file_data.file_uri)\n",
    "            else:\n",
    "                print(content)\n",
    "        else:\n",
    "            print(content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "a20c41820fc1"
   },
   "source": [
    "## Initialize Gemini"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "d80381cc7108",
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Gemini Config\n",
    "GENERATION_CONFIG = {\n",
    "    \"max_output_tokens\": 8192,\n",
    "    \"temperature\": 0.1,\n",
    "    \"top_p\": 0.95,\n",
    "}\n",
    "\n",
    "SAFETY_CONFIG = {\n",
    "    HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,\n",
    "    HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,\n",
    "    HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,\n",
    "    HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH,\n",
    "}\n",
    "\n",
    "gemini = GenerativeModel(model_name=\"gemini-2.0-flash-001\")\n",
    "audio_path_prefix = (\n",
    "    \"gs://public-aaie-genai-samples/gemini/prompting_recipes/multimodal/audio\"\n",
    ")\n",
    "\n",
    "\n",
    "def generate(\n",
    "    model,\n",
    "    contents,\n",
    "    safety_settings=SAFETY_CONFIG,\n",
    "    generation_config=GENERATION_CONFIG,\n",
    "    as_markdown=False,\n",
    "):\n",
    "    responses = model.generate_content(\n",
    "        contents=contents,\n",
    "        generation_config=generation_config,\n",
    "        safety_settings=safety_settings,\n",
    "        stream=False,\n",
    "    )\n",
    "    if isinstance(responses, list):\n",
    "        for response in responses:\n",
    "            if as_markdown:\n",
    "                display.display(display.Markdown(response.text))\n",
    "            else:\n",
    "                print(wrap(response.text), end=\"\")\n",
    "    else:\n",
    "        if as_markdown:\n",
    "            display.display(display.Markdown(responses.text))\n",
    "        else:\n",
    "            print(wrap(responses.text), end=\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "a7051fdeb787",
    "tags": []
   },
   "outputs": [],
   "source": [
    "display_audio(\n",
    "    audio_url=\"gs://public-aaie-genai-samples/gemini/prompting_recipes/multimodal/audio/sound_1.mp3\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "t8s94ynm1vGt"
   },
   "source": [
    "# Prompt #1. Audio Understanding\n",
    "\n",
    "This task requires the input to be presented in two different modalities: text and audio. The example of the API call is below, however this is non-optimal prompt and we can make it better."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "819f9eaab098",
    "tags": []
   },
   "outputs": [],
   "source": [
    "audio_path = f\"{audio_path_prefix}/sound_1.mp3\"\n",
    "audio_content = Part.from_uri(uri=audio_path, mime_type=\"audio/mp3\")\n",
    "prompt = \"\"\"Provide a description of the audio.\n",
    "The description should also contain anything important which people say in the audio.\"\"\"\n",
    "\n",
    "contents = [audio_content, prompt]\n",
    "# print_prompt(contents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "id": "85320b1f0f59",
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "This is an audio recording of CD2, an audio program to accompany English in Action 1, second edition, by Barbara H. Foley and Elizabeth R. Neblet. The copyright is 2018, National Geographic Learning, a part of Cengage Learning. The audio contains a section titled \"A. Listen and Repeat.\" The audio then lists the following sentences:\n",
       "\n",
       "1. He is eating.\n",
       "2. He is washing the car.\n",
       "3. She is listening to the radio.\n",
       "4. They are studying.\n",
       "5. He is cooking.\n",
       "6. She is sleeping.\n",
       "7. He is reading.\n",
       "8. She is drinking.\n",
       "9. They are talking.\n",
       "10. They are watching TV.\n",
       "11. He is doing his homework.\n",
       "12. She is cleaning the house.\n",
       "13. She is driving.\n",
       "14. They are walking.\n",
       "15. She is making lunch.\n",
       "16. He is doing the laundry."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "generate(gemini, contents, as_markdown=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_QJnFXeqAvaT"
   },
   "source": [
    "As we see the model correctly picked that this is a lesson in English, however we can improve the level of details."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ecIw8YDWISQf"
   },
   "source": [
    "# Prompt #2. Crafting an effective prompt\n",
    "\n",
    "To get the best results from Gemini for a task, think about both what you tell it and how you tell it.\n",
    "\n",
    "- What: Include all the necessary information to solve the task, like instructions, examples, and background details.\n",
    "- How:  Structure this information clearly.\n",
    "    - Order: Organize prompt in a logical sequence.\n",
    "    - Delimiters/Separators: Use headings or keywords to highlight key information. XML tags or Markdown headers are a good way to format.\n",
    "\n",
    "A well-structured prompt is easier for the model to understand and process, leading to more accurate and relevant responses.\n",
    "\n",
    "\n",
    "Let's rewrite the prompt and add a persona (or role), give clear goals, use XML tags as prompt separators."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "id": "MWnDgTHzAtqg",
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "Okay, here is a detailed description of the audio:\n",
       "\n",
       "The audio is an audio program to accompany English in Action 1, second edition, by Barbara H. Foley and Elizabeth R. Neblet. It is copyrighted in 2018 by National Geographic Learning, a part of Cengage Learning.\n",
       "\n",
       "The audio contains a series of sentences that are read aloud. The sentences describe various actions that people are doing. The listener is instructed to listen and repeat each sentence.\n",
       "\n",
       "Here is a list of the sentences that are read aloud:\n",
       "\n",
       "1. He is eating.\n",
       "2. He is washing the car.\n",
       "3. She is listening to the radio.\n",
       "4. They are studying.\n",
       "5. He is cooking.\n",
       "6. She is sleeping.\n",
       "7. He is reading.\n",
       "8. She is drinking.\n",
       "9. They are talking.\n",
       "10. They are watching TV.\n",
       "11. He is doing his homework.\n",
       "12. She is cleaning the house.\n",
       "13. She is driving.\n",
       "14. They are walking.\n",
       "15. She is making lunch.\n",
       "16. He is doing the laundry."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "prompt = \"\"\"You are an audio analyzer. You receive an audio and produce the \n",
    "detailed description about what happens in the audio.\n",
    "\n",
    "<INSTRUCTIONS>\n",
    "- Determine what happens in the audio\n",
    "- Understand the hidden meaning of the audio\n",
    "- If there are dialogues, identify the talking personas\n",
    "- Make sure the description is clear and helpful\n",
    "</INSTRUCTIONS>\n",
    "\n",
    "Now analyse the following audio\n",
    "\"\"\"\n",
    "\n",
    "contents = [audio_content, prompt]\n",
    "generate(gemini, contents, as_markdown=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QAzxT1LNB-Sj"
   },
   "source": [
    "With the updated prompt, we are able to capture much more details, although this prompt is rather generic and can be used for other audio files. Now let's add these changes as system instruction and see."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "OxLf3GkLJS6u"
   },
   "source": [
    "# Prompt #3. Using system instruction\n",
    "\n",
    "System Instruction (SI) is an effective way to steer Gemini's behavior and shape \n",
    "how the model responds to your prompt. SI can be used to describe model behavior \n",
    "such as persona, goal, tasks to perform, output format / tone / style, any constraints etc. \n",
    "\n",
    "SI behaves more \"sticky\" (or consistent) during multi-turn behavior. For example, \n",
    "if you want to achieve a behavior that the model will consistently follow, then \n",
    "system instruction is the best way to put this instruction.\n",
    "\n",
    "In this example, we will move the task rules to system instruction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "id": "3qDtLGxqYADf",
    "tags": []
   },
   "outputs": [],
   "source": [
    "system_prompt = \"\"\"You are an audio analyzer. You receive an audio and produce \n",
    "the detailed description about what happens in the audio.\n",
    "\n",
    "<INSTRUCTIONS>\n",
    "- Determine what happens in the audio\n",
    "- Understand the hidden meaning of the audio\n",
    "- If there are dialogues, identify the talking personas\n",
    "- Make sure the description is clear and helpful\n",
    "</INSTRUCTIONS>\n",
    "\"\"\"\n",
    "\n",
    "prompt = \"Now analyze the audio\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "id": "obWmXAilYFkX",
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "Okay, here is the analysis of the audio:\n",
       "\n",
       "**General Description:**\n",
       "The audio is an educational recording designed to accompany the \"English in Action 1\" textbook, second edition. It seems to be focused on teaching basic English vocabulary and grammar, specifically related to actions and present continuous tense.\n",
       "\n",
       "**Content Breakdown:**\n",
       "*   **Introduction:** A narrator introduces the audio program, mentioning the textbook it accompanies, the authors (Barbara H. Foley and Elizabeth R. Neblet), and the copyright information (2018, National Geographic Learning, a part of Cengage Learning).\n",
       "*   **Instructions:** A voice instructs the listener to \"Listen and repeat.\"\n",
       "*   **Vocabulary/Grammar Practice:** A series of numbered sentences are presented, each describing an action. The sentences are simple and use the present continuous tense (e.g., \"He is eating,\" \"She is washing the car\").\n",
       "\n",
       "**Talking Personas:**\n",
       "*   **Narrator:** A voice introduces the audio program and provides copyright information.\n",
       "*   **Instructor:** A voice gives instructions to the listener (e.g., \"Listen and repeat\").\n",
       "*   **Speakers:** Different voices (male and female) read the sentences describing the actions.\n",
       "\n",
       "**Hidden Meaning/Purpose:**\n",
       "The audio aims to help learners:\n",
       "*   Improve their listening comprehension skills.\n",
       "*   Practice pronunciation by repeating the sentences.\n",
       "*   Learn and reinforce vocabulary related to everyday actions.\n",
       "*   Understand and use the present continuous tense correctly.\n",
       "\n",
       "**Overall:**\n",
       "The audio is a straightforward and practical tool for English language learners, particularly beginners. It focuses on building foundational skills in listening, speaking, and grammar through repetition and simple sentence structures."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gemini_si = GenerativeModel(\n",
    "    model_name=\"gemini-2.0-flash-001\", system_instruction=system_prompt\n",
    ")\n",
    "\n",
    "contents = [audio_content, prompt]\n",
    "generate(gemini_si, contents, as_markdown=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "86NmGY798oMC"
   },
   "source": [
    "# Prompt #4. Audio Understanding: Get structured outputs\n",
    "\n",
    "Gemini models can generate structured outputs such as JSON, providing a blueprint for the model's output. This feature is also referred to as [controlled generation](https://developers.googleblog.com/en/mastering-controlled-generation-with-gemini-15-schema-adherence/). \n",
    "\n",
    "In this example, we demonstrate Gemini to return structured output (JSON) from a audio analysis. One of the ways to achieve better understanding of audio (or any multimodal) content is to prompt the model to explain its \"reasoning\" about the response. This has proven to be very effective method, however it can increase the latency. \n",
    "\n",
    "[Vertex AI Gemini API](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/control-generated-output) makes it easy to return JSON output by configuring response MIME type as `application/json`. Optionally, you can also configure `response_schema` with the JSON schema for the model to generate output as per the schema."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "7cfe2c6a4f5d",
    "tags": []
   },
   "outputs": [],
   "source": [
    "response_schema = {\n",
    "    \"type\": \"ARRAY\",\n",
    "    \"items\": {\n",
    "        \"type\": \"OBJECT\",\n",
    "        \"properties\": {\n",
    "            \"harmfulness_reasoning\": {\n",
    "                \"type\": \"STRING\",\n",
    "                \"description\": \"Step-by-step detailed reasoning about how harmful is the audio\",\n",
    "            },\n",
    "            \"harmfulness_score\": {\n",
    "                \"type\": \"INTEGER\",\n",
    "                \"description\": \"Number between 0 and 5 indicating how harmful is the audio\",\n",
    "            },\n",
    "        },\n",
    "        \"required\": [\"harmfulness_reasoning\", \"harmfulness_score\"],\n",
    "    },\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "id": "xF8owBa3Yi-G",
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[   {     \"harmfulness_reasoning\": \"The audio primarily contains instructional\n",
      "content for English language learning, featuring clear and neutral speech. There\n",
      "are no elements that could be considered harmful to children; it lacks any\n",
      "offensive language, violence, or suggestive themes. The overall tone is\n",
      "educational and safe for children of all ages.\",     \"harmfulness_score\": 1   }\n",
      "]"
     ]
    }
   ],
   "source": [
    "structured_prompt = \"\"\"You are an audio analyzer. You receive an audio and \n",
    "produce harmfulness score - how harmful this audio can be for kids.\"\"\"\n",
    "\n",
    "contents = [audio_content, structured_prompt]\n",
    "\n",
    "generate(\n",
    "    gemini,\n",
    "    contents,\n",
    "    generation_config=GenerationConfig(\n",
    "        response_mime_type=\"application/json\", response_schema=response_schema\n",
    "    ),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4ffoSV1vbMBZ"
   },
   "source": [
    "The model returned the correct score for the audio by asking the model to output \"reasoning\" along with the score. Adding \"reasoning\" field before the \"score\" gives a consistent and correct score. The intuition is  that LLM can generate \"reasoning\" first and rely on the thoughts to properly produce the score."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wSNrNDh2Ev0G"
   },
   "source": [
    "# Conclusion\n",
    "\n",
    "This demonstrated various examples of working with Gemini using audio files. Following are general prompting strategies when working with Gemini on multimodal prompts, that can help achieve better performance from Gemini:\n",
    "\n",
    "1. Craft clear and concise instructions.\n",
    "1. Add your video or any media first for single-media prompts.\n",
    "1. Add few-shot examples to the prompt to show the model how you want the task done and the expected output.\n",
    "1. Break down the task step-by-step.\n",
    "1. Specify the output format.\n",
    "1. Ask Gemini to include reasoning in its response along with decision or scores\n",
    "1. Use context caching for repeated queries.\n",
    "\n",
    "Specifically, when working with audio following may help:\n",
    "\n",
    "1. Ask Gemini to avoid summarizing for transcription.\n",
    "1. Add examples for effective speaker diarization."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "01db8cf611f3"
   },
   "source": [
    "---"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "multimodal_prompting_audio.ipynb",
   "toc_visible": true
  },
  "environment": {
   "kernel": "conda-base-py",
   "name": "workbench-notebooks.m128",
   "type": "gcloud",
   "uri": "us-docker.pkg.dev/deeplearning-platform-release/gcr.io/workbench-notebooks:m128"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
